﻿<!DOCTYPE HTML>
<!-- saved from url=(0092)http://172.13.19.31:6060/note_html/服务器/CentOS/11003-shell-grep、sed、awk与正则表达式.html -->
<!DOCTYPE html PUBLIC "" ""><HTML><HEAD><META content="IE=11.0000" 
http-equiv="X-UA-Compatible">
 
<META http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
<TITLE>shell-grep、sed、awk与正则表达式</TITLE> <LINK href="shell-grep、sed、awk与正则表达式_files/standalone.css" 
rel="stylesheet"> <LINK href="shell-grep、sed、awk与正则表达式_files/overlay-apple.css" 
rel="stylesheet"> <LINK href="shell-grep、sed、awk与正则表达式_files/article_edit.css" 
rel="stylesheet"> 
<STYLE type="text/css">
	#content{
		margin: 5px 10px;
	}
</STYLE>
	 <!-- 代码高亮 -->	 <LINK href="shell-grep、sed、awk与正则表达式_files/shCoreEclipse.css" 
rel="stylesheet">	 <LINK href="shell-grep、sed、awk与正则表达式_files/my-highlighter.css" 
rel="stylesheet"> 
<META name="GENERATOR" content="MSHTML 11.00.10586.545"></HEAD> 
<BODY>
<DIV id="content">
<H1 align="center">shell-grep、sed、awk与正则表达式</H1>
<P align="right" 
style="margin: 0px 10px 0px 0px; padding: 0px;">最后修改时间：2015-10-27 17:28:32</P>
<HR style="border-width: 2px; border-color: lime;">

<H3>grep与egrep</H3>
<H4>grep</H4>
<PRE class="brush: bash;">语法： grep [-cinvABC] ‘word’ filename

-c ：打印符合要求的行数

-i ：忽略大小写

-n ：在输出符合要求的行的同时连同行号一起输出

-v ：打印不符合要求的行

-A ：后跟一个数字（有无空格都可以），例如 –A2则表示打印符合要求的行以及下面两行

-B ：后跟一个数字，例如 –B2 则表示打印符合要求的行以及上面两行

-C ：后跟一个数字，例如 –C2 则表示打印符合要求的行以及上下各两行
</PRE>
<DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-17.png"></DIV></DIV>
<H4>示例</H4>
<UL>
  <LI>
  <DIV>
  <DIV align="left" 
  style="padding: 5px 0px;"><FONT>过滤出带有某个关键词的行并输出行号</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-18.png"></DIV></DIV></LI>
  <LI>
  <DIV>
  <DIV align="left" 
  style="padding: 5px 0px;"><FONT>过滤不带有某个关键词的行，并输出行号</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-19.png"></DIV></DIV></LI>
  <LI>
  <DIV>
  <DIV align="left" style="padding: 5px 0px;"><FONT>过滤出所有包含数字的行</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-20.png"></DIV>
  <DIV align="left" style="padding: 5px 0px;"><FONT>在前面也提到过这个”[ 
  ]”的应用，如果是数字的话就用[0-9]这样的形式，当然有时候也可以用这样的形式[15]即只含有1或者5，注意，它不会认为是15。如果要过滤出数字以及大小写字母则要这样写[0-9a-zA-Z]。另外[ 
  ]还有一种形式，就是[^字符] 表示除[ ]内的字符之外的字符。</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-21.png"></DIV>
  <DIV align="left" 
  style="padding: 5px 0px;"><FONT>这就表示筛选包含oo字符串，但是不包含r字符</FONT></DIV></DIV></LI>
  <LI>
  <DIV>
  <DIV align="left" 
  style="padding: 5px 0px;"><FONT>过滤出文档中以某个字符开头或者以某个字符结尾的行</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-22.png"></DIV>
  <DIV align="left" 
  style="padding: 5px 0px;"><FONT>在正则表达式中，”^”表示行的开始，”$”表示行的结尾，那么空行则表示”^$”,如果你只想筛选出非空行，则可以使用 
  “grep -v ‘^$’ filename”得到你想要的结果。现在想一下，如何打印出不以英文字母开头的行呢？</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-23.png"></DIV></DIV></LI>
  <LI>
  <DIV>
  <DIV align="left" style="padding: 5px 0px;"><FONT>过滤任意一个字符与重复字符</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-24.png"></DIV></DIV></LI>
  <LI>
  <DIV>
  <DIV align="left" style="padding: 5px 0px;"><FONT>指定要过滤字符出现的次数</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-25.png"></DIV>
  <DIV align="left" style="padding: 5px 0px;"><FONT>这里用到了{ 
  }，其内部为数字，表示前面的字符要重复的次数。上例中表示包含有两个o 即’oo’的行。注意，{ }左右都需要加上脱意字符’\’。另外，使用{ 
  }我们还可以表示一个范围的，具体格式是 
  ‘\{n1,n2\}’其中n1小于n2，表示重复n1到n2次前面的字符，n2还可以为空，则表示大于等于n1次</FONT></DIV></DIV></LI></UL>
<H4>egrep</H4>
<P 
style="text-indent: 0.8cm;">我们可以用egrep完成grep不能完成的工作，当然了grep能完成的egrep完全可以完成。如果你嫌麻烦，egrep了解一下即可，因为grep的功能已经足够可以胜任你的日常工作了。为了试验方便，test.txt 
编辑成如下内容： </P>
<PRE class="brush: bash;">rot:x:0:0:/rot:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

operator:x:11:0:operator:/rooot:/sbin/nologin

roooot:x:0:0:/rooooot:/bin/bash

1111111111111111111111111111111

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</PRE>
<UL>
  <LI>
  <DIV>
  <DIV align="left" style="padding: 5px 0px;"><FONT>筛选一个或一个以上前面的字符</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-26.png"></DIV></DIV></LI>
  <LI>
  <DIV>
  <DIV align="left" style="padding: 5px 0px;"><FONT>筛选零个或一个前面的字符</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-27.png"></DIV></DIV></LI>
  <LI>
  <DIV>
  <DIV align="left" 
  style="padding: 5px 0px;"><FONT>筛选字符串1或者字符串2，中间有一个’|’表示或者的意思</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-28.png"></DIV></DIV></LI>
  <LI>
  <DIV>
  <DIV align="left" style="padding: 5px 0px;"><FONT>egrep中’( )’的应用，用’( 
  )’表示一个整体，例如(oo)+就表示1个’oo’或者多个’oo’</FONT></DIV>
  <DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-29.png"></DIV></DIV></LI></UL>
<H3>sed 工具的使用</H3>
<H4>简介</H4>
<P style="text-indent: 0.8cm;">grep 
工具的功能其实还不够强大，其实说白了，grep实现的只是查找功能，而它却不能实现把查找的内容替换掉。以前用vim的时候，可以查找也可以替换，但是只局限于在文本内部来操作，而不能输出到屏幕上。sed工具以及下面要讲的awk工具就能实现把替换的文本输出到屏幕上的功能了，而且还有其他更丰富的功能。sed和awk都是流式编辑器，是针对文档的行来操作的 
</P>
<H4>示例</H4>
<DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-30.png"></DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-31.png"></DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-32.png"></DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-33.png"></DIV>
<DIV align="left" 
style="padding: 5px 0px;"><FONT>这个就需要解释一下了，上例中用’()’把所想要替换的字符括起来成为一个整体，因为括号在sed中属于特殊符号，所以需要在前面加脱意字符’\’，替换时则写成’\1’, 
‘\2’, ‘\3’ 的形式。除了调换两个字符串的位置外，还常常用到在某一行前或者后增加指定内容</FONT></DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-34.png"></DIV>
<DIV align="left" style="padding: 5px 0px;"><FONT>g.替换文本的某一行的内容</FONT></DIV>
<DIV align="left" style="padding: 5px 0px;"><FONT>sed -i '2ckkk' 
text.txt。将text.txt的第二行替换成kkk。命令中c是替换命令，行的替换</FONT></DIV></DIV>
<H4>示例</H4>
<PRE class="brush: bash;">[d删除命令]

$ sed ‘2d’ file          #删除file中的第2行

$ sed ‘2,$d’ file            #删除第2行到最后一行的所有行

$ sed ‘/hello/’ file      #删除包含hello的行

$ sed ‘1d;5d;10d’ file    #删除第1，5，10行

$ sed ‘/^$/d’ file        #删除file中的空行

$ sed ‘5,10!d’ file       #删除5-10以外的所有行

总结：d命令有三种地址模式，行号，行中字符串片段，正则表达式，对于后两种需要使用//包围地址，如/hello/和/^$/，还有一点，两个地址间的逗号，
表示作用范围为两个地址之间，！代表取补集

 

[s 替换命令]

$ sed ‘s/test/Test/’ file              #用Test替换每行中第一个test

$ sed ‘s/test/Test/5’ file              #用Test替换每行中第5个出现的test

$ sed ‘s/test/Test/g’ file              #用Test替换每行中所有test

$ sed –n‘s/^test/Test/p’ file          #-n与p合用，仅显示发生替换操作的行，

#Test替换以test开头的行的开头的test

$ sed ‘s/^192.168.0.1/&amp;localhost’ file  # &amp;表示匹配到的内容，用

#192.168.0.1localhost替换以192.168.0.1

#开头的行的开头的192.168.0.1

$ sed –n‘s/loveable/\1rs/p’ file   #\1代表love匹配到的内容，用lovers

#替换包含love的行中第一个出现的love

$ sed ‘s#10#100#g’ file                 #用100代替每行出现的10，这里#等于/

$ sed –n‘/test/,/check/p’ file         #仅打印第一包含test的行到第一个包含

#check的行之间的所有行

$ sed –n‘5,/^test/p’ file              #打印第5行到第一个以test开头的行

#之间的所有行

$ sed ‘/test/,/check/s/$/HelloEnd’      #在第一个包含到第一个包含check的行

#后边追加HelloEnd

$ sed –e‘1,5d’–e‘s/test/check/’ file  #删除1-5行的内容，将文件中每行第一个

#test替换为check，前边命令影响后边命令

总结：命令中体现了p命令的使用，通常与-n选项连用，s命令是最常用的，注意分隔符可以用其他符号代替，注意逗号可以表示地址区间，以及//包围地址的使用

 

[n下一行命令]

$ sed ‘/test/{n;s/aa/bb/}’ file       #读到含test的行，输出该行，然后

#读入下一行，用bb替换下一行出现

#的第一个aa，循环执行以上动作

该命令可以写为以下方式

$ sed ‘/test/{  &lt;键入换行符&gt;

&gt;n  &lt;键入换行符&gt;

&gt;s/aa/bb &lt;键入换行符&gt;

&gt;}’ file

总结：n命令前边的命令不会作用于下一行，n命令后边的命令不会作用于当前行

[r 文件读入命令]

$ sed ‘/test/rfile2’ file1    #将file2的内容插入到file1中含有test的每一行之后

[w 文件写入命令]

$ sed ‘/test/wfile2’ file1   #将file1中每个含有文本test的行追加到file2中

[a 追加命令]

$ sed ‘/test/a\thisis append line’ file #在含有文本test的行后边插入一行内容为

                                        #thisis append line的文本

[i 插入命令]

$ sed ‘/test/i\thisis a insert line’ file #类似如a命令，在对应行前边插入


    在b.txt的第2行之前插入“xxx”

    sed '2 i/xxx' b.txt
 

    在b.txt的第2行之后插入“xxx”

 
    sed '2 a/xxx' b.txt
 

    在b.txt的第2行和第3行之后插入“xxx”

    sed '2,3 a/xxx' b.txt
 

    在b.txt的第2行和第3行之前插入“xxx”

    sed '2,3 i/xxx' b.txt

    在b.txt的第2行至最后一行之前插入“xxx”

    sed '2,$ i/xxx' b.txt

[c 替换命令]

$ sed ‘3,5c\thisis a change line’file    #将文件file的第3-5行内容替换为一行，

                                          #其内容为this is a change line

[y 转换命令]

$ sed ‘1,10y/abcd/ABCD/’ file      #将file前10行中所有的字符a,b,c,d转换为大写

[q 退出命令]

$ sed ‘10q’ file                   #处理完（默认为打印）第10行，sed命令结束

                                  #q命令与b,t等命令可以用于流程控制

[N 下一行追加命令]

问题描述：用sed实现去换行的功能，即tr –d‘\n’的功能

sed –fscript.file file   #其中script.file为sed脚本文件，名字可以随便取

                          #file为待处理文件

Script.file脚本文件内容如下：

 

{

N             #将下一行追加到模式空间，现在空间中有两行内容，中间用\n分隔

s/\n//        #删除\n,执行完这里sed对下一行继续处理

}

当然，左大括号{左边可以通过加地址信息限制处理哪几行，这个功能当然可以不写脚本文件，直接在命令行执行，如下：

sed ‘N;s/\n//’ file

再强调一次，脚本文件都可以写成命令行方式，放过来也成立，就是看你觉得怎么方便而已！

 

[N P D 循环] #联合使用N-P-D，操作控制流

问题描述：如下文本文件，如果UNIX System出现以下情况：UNIX是一行的最后一个单词，System是下一行的第一个单词，
则将UNIX System替换为UNIX Operating System，新的换行符在System之后。

file内容如下：

Here are examples of the UNIX

System. Where UNIX

System appears, it should be the UNIX

Operating System.

处理后输出结果为：

Here are examples of the UNIX Operating System.

Where UNIX Operating System appears, it should be theUNIX

Operating System.

 

实现脚本如下：

/UNIX$/{

    N   #在UNIX结尾的行后追加下一行，中间有\n分隔

    s/\nSystem.∗/ Operating \1\n/  #替换,这里的特殊用法稍后讲述

    P   #输出\n之前的内容

D   #删除\n之前的内容，并跳转至脚本第一行，即/UNIX$/{处

}

 

备注：N是在模式空间追加一行，两行之间有一个分隔符\n；P是打印多行模式空间中第一个\n之前的内容，也就是第一行；D是删除第一个\n之前的内容，
并使得控制流程跳转至脚本第一行，如果D后边还有命令，执行D后，后边的命令式执行不到的。

 

如果将脚本中替换命令那行换为以下一句，输出结果略有不同：

s/\nSystem/ Operating System\n/

输出结果为：

Here are examples of the UNIX Operating System

.Where UNIX Operating System

 appears, itshould be the UNIX

Operating System.

 

这里面有一些标点的问题，因此，我们做了特别处理，说明如下：

System.∗代表System后边有一个任意字符，这是为了处理空格和句号的，后边*前边有个空格，这里看不出来，实际是输入了一个空格，这个代表，之后出现0个或多个空格，
而其中用反斜杠和小括号括起来，代表后边\1指的就是这个匹配。如果这里有不明白的，可以翻看前边关于和\1的介绍。

[h,H,g,G,x模式空间与备份空间命令]

这几个命令就是在两个空间中互相操作，比较好理解，这里不再举例。

[b,t]流程跳转命令，根据前边的理论介绍也比较好理解，不再举例。
</PRE>
<H4>练习</H4>
<PRE class="brush: bash;">1. 把/etc/passwd 复制到/root/test.txt，用sed打印所有行；

2. 打印test.txt的3到10行；

3. 打印test.txt 中包含’root’的行；

4. 删除test.txt 的15行以及以后所有行；

5. 删除test.txt中包含’bash’的行；

6. 替换test.txt 中’root’为’toor’；

7. 替换test.txt中’/sbin/nologin’为’/bin/login’

8. 删除test.txt中5到10行中所有的数字；

9. 删除test.txt 中所有特殊字符（除了数字以及大小写字母）；

10. 把test.txt中第一个单词和最后一个单词调换位置；

11. 把test.txt中出现的第一个数字和最后一个单词替换位置；

12. 把test.txt 中第一个数字移动到行末尾；

13. 在test.txt 20行到末行最前面加’aaa:’；

现在给出以上练习题的答案，你如果实在想不出如何操作，那你看看答案吧，请尽量多想一下。

1. /bin/cp /etc/passwd /root/test.txt ; sed -n '1,$'p test.txt

2. sed -n '3,10'p test.txt

3. sed -n '/root/'p test.txt

4. sed '15,$'d test.txt

5. sed '/bash/'d test.txt

6. sed 's/root/toor/g' test.txt

7. sed 's#sbin/nologin#bin/login#g' test.txt

8. sed '5,10s/[0-9]//g' test.txt

9. sed 's/[^0-9a-zA-Z]//g' test.txt

10. sed 's/\(^[a-zA-Z][a-zA-Z]*\)\([^a-zA-Z].*\)\([^a-zA-Z]\)\([a-zA-Z][a-zA-Z]*$\)/\4\2\3\1/' test.txt

11. sed 's#\([^0-9][^0-9]*\)\([0-9][0-9]*\)\([^0-9].*\)\([^a-zA-Z]\)\([a-zA-Z][a-zA-Z]*$\)#\1\5\3\4\2#' test.txt

12. sed 's#\([^0-9][^0-9]*\)\([0-9][0-9]*\)\([^0-9].*$\)#\1\3\2#' test.txt

13. sed '20,$s/^.*$/aaa:&amp;/' test.txt
</PRE>
<H3>awk工具的使用</H3>
<H4>简介</H4>
<P style="text-indent: 0.8cm;">
上面也提到了awk和sed一样是流式编辑器，它也是针对文档中的行来操作的，一行一行的去执行。awk比sed更加强大，它能做到sed能做到的，同样也能做到sed不能做到的。awk工具其实是很复杂的，有专门的书籍来介绍它的应用，但是学那么复杂没有必要，只要能处理日常管理工作中的问题即可。这里仅介绍比较常见的awk应用，如果你感兴趣的话，再去深入研究吧。 
</P>
<H4>示例</H4>
<DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-35.png"></DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-36.png"></DIV>
<DIV align="left" 
style="padding: 5px 0px;"><FONT>awk中是可以用逻辑符号判断的，比如’==’就是等于，也可以理解为“精确匹配”。另外也有’&gt;’, 
‘&gt;=’, ‘&lt;’, ‘&lt;=’, ‘!=’ 
等等，值得注意的是，即使$3为数字，awk也不会把它当数字看待，它会认为是一个字符。所以不要妄图去拿$3当数字去和数字做比较。</FONT></DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-37.png"></DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-38.png"></DIV>
<DIV align="left"><IMG alt="图片不存在" src="shell-grep、sed、awk与正则表达式_files/20150827-39.png"></DIV></DIV>
<H4>练习</H4>
<PRE class="brush: bash;">1. 用awk 打印整个test.txt （以下操作都是用awk工具实现，针对test.txt）；

2. 查找所有包含’bash’的行；

3. 用’:’作为分隔符，查找第三段等于0的行；

4. 用’:’作为分隔符，查找第一段为’root’的行，并把该段的’root’换成’toor’(可以连同sed一起使用)；

5. 用’:’作为分隔符，打印最后一段；

6. 打印行数大于20的所有行；

7. 用’:’作为分隔符，打印所有第三段小于第四段的行；

8. 用’:’作为分隔符，打印第一段以及最后一段，并且中间用’@’连接 （例如，第一行应该是这样的形式 “root@/bin/bash”；

9. 用’:’作为分隔符，把整个文档的第四段相加，求和；

下面给出答案：

1. awk '{print $0}' test.txt

2. awk '/bash/' test.txt

3. awk -F':' '$3=="0"' test.txt

4. awk -F':' '$1=="root"' test.txt |sed 's/root/toor/'

5. awk -F':' '{print $NF}' test.txt

6. awk -F':' 'NR&gt;20' test.txt

7. awk -F':' '$3&lt;$4' test.txt

8. awk -F':' '{print $1"@"$NF}' test.txt

9. awk -F':' '{(sum+=$4)}; END {print sum}' test.txt
</PRE>
<HR style="border-width: 2px; border-color: lime;">

<DIV align="center">©copyright 版权所有   作者：zzy</DIV>
<SCRIPT src="../../pub/syntaxhighlighter/scripts/shCore.js" type="text/javascript"></SCRIPT>
 
<SCRIPT src="../../pub/syntaxhighlighter/scripts/shBrushJava.js" type="text/javascript"></SCRIPT>
	
<SCRIPT src="../../pub/syntaxhighlighter/scripts/shBrushJScript.js" type="text/javascript"></SCRIPT>
 
<SCRIPT src="../../pub/syntaxhighlighter/scripts/shBrushXml.js" type="text/javascript"></SCRIPT>
 
<SCRIPT src="../../pub/syntaxhighlighter/scripts/shBrushSql.js" type="text/javascript"></SCRIPT>
 
<SCRIPT src="../../pub/syntaxhighlighter/scripts/shBrushBash.js" type="text/javascript"></SCRIPT>
	
<SCRIPT src="../../pub/syntaxhighlighter/scripts/shBrushVb.js" type="text/javascript"></SCRIPT>
	
<SCRIPT src="../../pub/syntaxhighlighter/init.js" type="text/javascript"></SCRIPT>
 
<SCRIPT src="../../pub/js/jquery.tools.min.js" type="text/javascript"></SCRIPT>
 <!-- make all links with the 'rel' attribute open overlays --> 
<SCRIPT>
  $(function() {
      $("#apple img[rel]").overlay({effect: 'apple'});
    });
</SCRIPT>
 </DIV></BODY></HTML>
